package xj.graph2d.app.project;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.w3c.dom.Element;

import xj.app.Application;
import xj.graph2d.Document;
import xj.graph2d.DocumentException;
import xj.lang.CodeWriter;

public class ProjectManager {

  public ProjectManager(Application app) {
    this(app, "Default", ProjectType.Default);
  }

  public ProjectManager(Application app, String projName, ProjectType projType) {
    this.app = app;
    currentProject = defaultProject = new Project(app, projName, projType);
    addProject(currentProject);
    defaultProjectName = projName;
    defaultProjectType = projType;
    // testDefaulProject();
  }

  public ProjectListener getProjectListener() {
    return listener;
  }

  public void setProjectListener(ProjectListener listener) {
    this.listener = listener;
  }

  public void addProject(Project project) {
    addProject(project, true);
  }

  public void addProject(Project project, boolean notify) {
    if (project != null) {
      projects.add(project);
      currentProject = project;
      if (notify && listener != null) {
	listener.projectAdded(project);
      }
    }
  }

  public void removeProject(Project project) {
    removeProject(project, true);
  }

  public void removeProject(Project project, boolean notify) {
    if (project != null) {
      projects.remove(project);
      if (notify && listener != null) {
	listener.projectRemoved(project);
      }
    }
  }

  public boolean isDefaultProject(Project project) {
    return (project != null && 
	    project == defaultProject);
  }

  public Project getDefaultProject() {
    return defaultProject;
  }

  public Project getCurrentProject() {
    if (currentProject == null && 
	projects.size() > 0) {
      currentProject = projects.get(0);
    }
    return currentProject;
  }

  public void setCurrentProject(Project currentProject) {
    this.currentProject = currentProject;
  }

  public void saveCurrentProject() throws IOException, DocumentException {
    if (currentProject != null) {
      currentProject.saveProject();
    }
  }

  public ProjectItem getCurrentItem() {
    return currentItem;
  }

  public void setCurrentItem(ProjectItem currentItem) {
    this.currentItem = currentItem;
  }

  public Iterator<Project> allProjects() {
    return projects.iterator();
  }

  public void addProjectItem(ProjectItem item, ProjectFolder parent) {
    addProjectItem(item, parent, -1, true);
  }

  public void addProjectItem(ProjectItem item, 
			     ProjectFolder parent, 
			     int pos) {
    addProjectItem(item, parent, pos, true);
  }

  public void addProjectItem(ProjectItem item, 
			     ProjectFolder parent, 
			     boolean notify) {
    addProjectItem(item, parent, -1, notify);
  }

  public void addProjectItem(ProjectItem item, 
			     ProjectFolder parent,
			     int pos,
			     boolean notify) {
    if (item != null && parent != null) {
      if (pos < 0) { 
	parent.addItem(item);
      } else { 
	parent.addItem(item, pos);
      }
      if (notify && listener != null) {
	listener.projectItemAdded(item, pos);
      }
    }
  }

  public void removeProjectItem(ProjectItem item) {
    removeProjectItem(item, true);
  }

  public void removeProjectItem(ProjectItem item, boolean notify) {
    if (item != null) {
      ProjectFolder parent = item.getParent();
      if (parent != null) {
	parent.removeItem(item);
	if (notify && listener != null) {
	  listener.projectItemRemoved(item);
	}
      }
    }
  }

  public void saveProject(Project project) throws IOException,
      DocumentException {
    if (project != null) {
      project.saveProject();
      // project.saveAllDocuments();
    }
  }

  public void saveAllProjects() throws IOException, DocumentException {
    Iterator<Project> iter = projects.iterator();
    while (iter.hasNext()) {
      Project project = iter.next();
      project.saveProject();
    }
  }

  public boolean hasProject(String name) {
    if (name != null) {
      Iterator<Project> iter = projects.iterator();
      while (iter.hasNext()) {
	Project project = iter.next();
	if (name.equals(project.getName())) {
	  return true;
	}
      }
    }
    return false;
  }

  public boolean containsProject(Project project) {
    if (project != null) {
      return projects.contains(project);
    }
    return false;
  }

  public Project findProject(String name) {
    if (name != null) {
      Iterator<Project> iter = projects.iterator();
      while (iter.hasNext()) {
	Project project = iter.next();
	if (name.equals(project.getName())) {
	  return project;
	}
      }
    }
    return null;
  }

  public ProjectItem findItem(String projname, Document doc) {
    if (projname != null) {
      Project proj = findProject(projname);
      if (proj != null) {
	return proj.findItem(doc);
      }
      return null;
    } else {
      return findItem(doc);
    }
  }

  public ProjectItem findItem(Document doc) {
    if (doc != null) {
      Iterator<Project> iter = projects.iterator();
      while (iter.hasNext()) {
	Project project = iter.next();
	ProjectItem item = project.findItem(doc);
	if (item != null) {
	  return item;
	}
      }
    }
    return null;
  }

  public boolean hasChangedProjects() {
    Iterator<Project> iter = projects.iterator();
    while (iter.hasNext()) {
      Project project = iter.next();
      if (project.hasChangedItems()) {
	return true;
      }
    }
    return false;
  }

  public String getNewProjectName(String prefix) {
    if (prefix == null) {
      prefix = "Project";
    }
    int i = 1;
    String wd = app.getDefaultDir();
    System.out.println("ProjectManager.getNewProjectName() " + wd);

    String newProjectName = (prefix + i);
    while (true) {
      if (!hasProject(newProjectName)) {
	String filename;
	if (wd != null) { 
	  filename = wd + File.separator + newProjectName;
	} else { 
	  filename = newProjectName;
	}
	File file = new File(filename);
	if (!file.exists()) { 
	  // dir does not exist 
	  filename = filename + "." + Project.PROJECT_FILE_SUFFIX;
	  if (!file.exists()) { 
	    // project file does not exist 
	    break;
	  }
	}
      }
      newProjectName = (prefix + (++i));
    }
    return newProjectName;
  }

  public int getNumOfProjects() {
    return projects.size();
  }

  public List<Project> getProjects() {
    return projects;
  }

  public void save(CodeWriter out) {
    if (out != null) {
      String curproj = null;
      if (currentProject != null) {
	curproj = currentProject.getName();
      }
      if (curproj != null) { 
	out.println("<ProjectManager current=\'" + curproj + "\'>");
      } else { 
	out.println("<ProjectManager>");
      }
      out.thisIndentInc();

      Iterator<Project> iter = projects.iterator();
      while (iter.hasNext()) {
	Project project = iter.next();
	out.println("<Project name=\'" + project.getName() + 
		    "\' path=\'" + project.getProjectFilename() + "\'/>");
      }

      out.thisIndentDec();
      out.println("</ProjectManager>");
    }
  }

  public void load(Element pm) {

  }

  public void setDefaultItemNameType(String name, Document.DocumentType type) {
    if (name != null) {
      defaultItemName = name;
    }
    if (type != null) {
      defaultItemType = type;
    }
  }

  public String getDefaultItemName() {
    return defaultItemName;
  }

  public String getNewDefaultItemName() {
    return (defaultItemName + (defaultItemNameCounter++));
  }

  public Document.DocumentType getDefaultItemType() {
    return defaultItemType;
  }

  public void removeUnsavedNewProjects() {
    //System.out.println("ProjectManager.removeUnsavedNewProjects()"); 
    
    Iterator<Project> iter = projects.iterator();
    while (iter.hasNext()) {
      Project project = iter.next();
      project.removeUnsavedNewItems();
      if (project.isEmpty()) { 
	//System.out.println("ProjectManager.removeUnsavedNewProjects() remove " + project.getName()); 
	iter.remove();
      }
    }
  }

  protected Application app;

  protected ProjectListener listener;

  protected Project currentProject;

  protected Project defaultProject;

  protected ProjectItem currentItem;

  protected static int defaultItemNameCounter = 1;

  protected List<Project> projects = new ArrayList<Project>();

  protected String defaultProjectName = "Project1";
  protected ProjectType defaultProjectType = ProjectType.UML;
  protected String defaultItemName = "ClassDiagram";
  protected Document.DocumentType defaultItemType = Document.DocumentType.UML_Class_Diagram;

  protected void testDefaulProject() {
    ProjectFolder f1 = new ProjectFolder("Folder1");
    ProjectFolder f2 = new ProjectFolder("Folder2");
    ProjectFolder f3 = new ProjectFolder("Folder3");
    ProjectFolder f4 = new ProjectFolder("Folder4");

    ProjectItem i01 = new ProjectItem("Item01");
    ProjectItem i02 = new ProjectItem("Item02");
    ProjectItem i03 = new ProjectItem("Item03");
    ProjectItem i1 = new ProjectItem("Item1");
    ProjectItem i2 = new ProjectItem("Item2");
    ProjectItem i3 = new ProjectItem("Item3");
    ProjectItem i4 = new ProjectItem("Item4");
    ProjectItem i5 = new ProjectItem("Item5");

    f1.addItem(f2);
    f1.addItem(i1);
    f2.addItem(i2);
    f3.addItem(i3);
    f4.addItem(i4);
    f4.addItem(i5);

    currentProject.addItem(i01);
    currentProject.addItem(i02);
    currentProject.addItem(i03);
    currentProject.addItem(f1);
    currentProject.addItem(f3);
    currentProject.addItem(f4);

  }

}
